﻿using System;
using System.Linq.Expressions;

namespace RuntimeHelloWorlds
{
	/// <summary>
	/// Best to look at the ExpressionHelloWorld sample first if you're not familiar
	/// with Expressions in .NET.
	/// 
	/// This sample uses the Expression-supported visitor pattern to modify an
	/// expression to call Console.WriteLine to output Hello, World! 
	/// </summary>
	public class ExpressionVisitorHelloWorld
	{
		public void SayHelloWorld()
		{
			// start with the lambda expression that outputs "(Expression Visitor)"
			Expression<Action> expression = () => ExpressionVisitorHelloWorld.OriginalMethod();

			// now visit it this expression, which just replaces it wtih an 
			// expression that outputs "Hello, World! " then calls the original
			// code:
			HelloWorldVisitor visitor = new HelloWorldVisitor();
			expression = visitor.Modify(expression) as Expression<Action>;
			LambdaExpression lambdaHwe = expression as LambdaExpression;
			Action helloWorld = (Action)lambdaHwe.Compile();
			helloWorld();
		}

		public static void OriginalMethod()
		{
			Console.WriteLine("(Expression Visitor)");
		}
	}

	public class HelloWorldVisitor : ExpressionVisitor
	{
		public Expression Modify(Expression exp)
		{
			return Visit(exp);
		}

		protected override Expression VisitLambda<T>(Expression<T> node)
		{
			return Expression.Lambda(
				Expression.Block(
					Expression.Call(
						// a shortcut way of getting to a MethodInfo instance:
						new Action<string>(Console.Write).Method,
						Expression.Constant("Hello, World! ")),
						base.Visit(node.Body)
						));
		}
	}
}
